using System;
using System.Collections.Generic;
using System.Text;
using BizTalkCop.Rules.Bases;
using Microsoft.FxCop.Sdk;
using BizTalkCop.Rules.Enums;
using System.Xml.XPath;
using System.Xml;
using BizTalkCop.Rules.Helpers;

namespace BizTalkCop.Rules.Naming.Rules
{
    /// <summary>
    /// Rule verifying orchestration types have the correct suffix
    /// </summary>
    /// <remarks>
    /// Checks type names for: port types and ports
    /// </remarks>
    public class OrchestrationTypesShouldHaveCorrectSuffix : OrchestrationRuleBase
    {
        /// <summary>
        /// Default constructor
        /// </summary>
        public OrchestrationTypesShouldHaveCorrectSuffix() : base("OrchestrationTypesShouldHaveCorrectSuffix") { }

        private Dictionary<OMElementType, string> _typeSuffixes;
        private Dictionary<OMElementType, string> TypeSuffixes
        {
            get
            {
                if (_typeSuffixes == null)
                {
                    _typeSuffixes = new Dictionary<OMElementType, string>();
                    foreach (string settingName in this.Settings.Keys)
                    {
                        OMElementType elementType = EnumHelper.Parse<OMElementType>(settingName);
                        if (elementType != OMElementType.Null)
                        {
                            _typeSuffixes.Add(elementType, this.Settings[settingName].ToString());
                        }
                    }
                }
                return _typeSuffixes;
            }
        }

        /// <summary>
        /// Checks if the orchestrations types are correctly suffixed
        /// </summary>
        /// <param name="type">Type to check</param>
        /// <returns>Problem collection</returns>
        public override ProblemCollection Check(TypeNode type)
        {
            if (IsOrchestration(type))
            {
                foreach (OMElementType elementType in TypeSuffixes.Keys)
                {
                    XPathNodeIterator elements = GetOMElements(type, elementType);
                    this.CheckElements(elements, elementType, type);
                }
            }
            return Problems;
        }

        private void CheckElements(XPathNodeIterator elements, OMElementType elementType, TypeNode type)
        {
            foreach (XPathNavigator navigator in elements)
            {
                string name = SelectSingleNode(navigator, XPathQuery.OMNamePropertyNode).Value;
                string suffix = TypeSuffixes[elementType];
                if (!name.EndsWith(suffix))
                {
                    Problems.Add(new Problem(GetNamedResolution("Suffix", name, suffix), type));
                }
            }            
        }

        #region Configured settings

        static OrchestrationTypesShouldHaveCorrectSuffix()
        {
            Dictionary<string, string> defaults = new Dictionary<string, string>();
            defaults.Add(Setting.PortType, Default.PortType);
            defaults.Add(Setting.PortDeclaration, Default.PortDeclaration);
            SetDefaults(typeof(OrchestrationTypesShouldHaveCorrectSuffix), defaults);
        }

        private struct Setting
        {
            public const string PortType = "PortType";
            public const string PortDeclaration = "PortDeclaration";
        }

        private struct Default
        {
            public const string PortType = "PortType";
            public const string PortDeclaration = "Port";
        }

        #endregion
    }
}
